package ${basepackage}.framework.service;

import java.io.Serializable;
import java.sql.Timestamp;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.hibernate.CallbackException;
import org.hibernate.EmptyInterceptor;
import org.hibernate.type.Type;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import ${basepackage}.framework.base.dao.BaseEntity;
import ${basepackage}.framework.base.intecepter.IAuditLog;
import ${basepackage}.framework.base.util.AppConstant;
import ${basepackage}.framework.base.util.Utils;
import ${basepackage}.framework.dao.AuditLogDAO;
import ${basepackage}.framework.model.AuditLog;

@Service
/**
 * @author Xi Wei
 * @version 1.0
 * @since 1.0
 */
public class AuditLogIntercepter extends EmptyInterceptor {

	@Autowired
	private AuditLogDAO auditLogDAO;
	private Set inserts = new HashSet();
	private Set updates = new HashSet();
	private Set deletes = new HashSet();

	@Override
	public String onPrepareStatement(String sql) {
		System.out.println("execute sql: " + sql);
		return super.onPrepareStatement(sql);
	}

	public boolean onSave(Object entity, Serializable id, Object[] state,
			String[] propertyNames, Type[] types) throws CallbackException {

		System.out.println("onSave");

		if (entity instanceof IAuditLog && entity instanceof BaseEntity) {
			inserts.add(entity);
		}

		if (entity instanceof BaseEntity) {
			for (int i = 0; i < propertyNames.length; i++) {
				if ("createUserId".equals(propertyNames[i])) {
					state[i] = getCurrentUser();
				} else if ("createDate".equals(propertyNames[i])) {
					state[i] = new Timestamp(System.currentTimeMillis());
				} else if ("updateUserId".equals(propertyNames[i])) {
					state[i] = getCurrentUser();
				} else if ("updateDate".equals(propertyNames[i])) {
					state[i] = new Timestamp(System.currentTimeMillis());
				}

			}

		}
		
		System.out.println("propertyNames in onSave = ");
		printArray(propertyNames);
		System.out.println("state in on Save= ");
		printArray(state);

		return false;

	}

	private long getCurrentUser() {
		// TODO Auto-generated method stub
		return Utils.getLoginId();
	}

	public boolean onFlushDirty(Object entity, Serializable id,
			Object[] currentState, Object[] previousState,
			String[] propertyNames, Type[] types) throws CallbackException {

		System.out.println("onFlushDirty");

		
		if (currentState != null) {
			for (Object o : currentState) {
				System.out.println("o = " + o);
			}
		}
		if (entity instanceof IAuditLog && entity instanceof BaseEntity) {
			updates.add(entity);
		}

		if (entity instanceof BaseEntity) {
			
			for (int i = 0; i < propertyNames.length; i++) {
			
				if ("createUserId".equals(propertyNames[i])) {
					if(currentState[i] == null){
						currentState[i] = getCurrentUser();
					}
					
				} else if ("createDate".equals(propertyNames[i])) {
					if(currentState[i] == null){
						currentState[i] = new Timestamp(System.currentTimeMillis());
					}
				} else if ("updateUserId".equals(propertyNames[i])) {
					currentState[i] = getCurrentUser();
				} else if ("updateDate".equals(propertyNames[i])) {
					currentState[i] = new Timestamp(System.currentTimeMillis());
				}

			}
		}
		System.out.println("propertyNames in onFlushDirty = ");
		printArray(propertyNames);
		System.out.println("state in onFlushdirty = ");
		printArray(currentState);
		System.out.println("previousState in onFlushdirty = ");
		printArray(previousState);
		return false;

	}
	
	private void printArray(Object[] array){
		System.out.println("{");
		for(int i = 0;i<array.length;i++){
			System.out.println(array[i]);
		}
		System.out.println("}");
	}

	public void onDelete(Object entity, Serializable id, Object[] state,
			String[] propertyNames, Type[] types) {

		System.out.println("onDelete");

		if (entity instanceof IAuditLog && entity instanceof BaseEntity) {
			deletes.add(entity);
		}
	}

	// called before commit into database
	public void preFlush(Iterator iterator) {
		System.out.println("preFlush");
	}

	// called after committed into database
	public void postFlush(Iterator iterator) {
		System.out.println("postFlush");

		try {

			for (Iterator it = inserts.iterator(); it.hasNext();) {
				IAuditLog entity = (IAuditLog) it.next();
				System.out.println("postFlush - insert");

				AuditLog auditRecord = new AuditLog(
						AppConstant.AUDITLOG_ACTION_NEW, entity.getLogDeatil(),
						new Timestamp(System.currentTimeMillis()),
						entity.getLogId(), entity.getClass().toString());

				auditLogDAO.save(auditRecord);
			}

			for (Iterator it = updates.iterator(); it.hasNext();) {
				IAuditLog entity = (IAuditLog) it.next();
				System.out.println("postFlush - update");
				AuditLog auditRecord = new AuditLog(
						AppConstant.AUDITLOG_ACTION_UPDATED,
						entity.getLogDeatil(), new Timestamp(
								System.currentTimeMillis()), entity.getLogId(),
						entity.getClass().toString());

				auditLogDAO.save(auditRecord);
			}

			for (Iterator it = deletes.iterator(); it.hasNext();) {
				IAuditLog entity = (IAuditLog) it.next();
				System.out.println("postFlush - delete");
				AuditLog auditRecord = new AuditLog(
						AppConstant.AUDITLOG_ACTION_Deleted,
						entity.getLogDeatil(), new Timestamp(
								System.currentTimeMillis()), entity.getLogId(),
						entity.getClass().toString());

				auditLogDAO.save(auditRecord);
			}

		} finally {
			inserts.clear();
			updates.clear();
			deletes.clear();
		}
	}
}
